#ifndef _NTH_LIB_H
#define _NTH_LIB_H

#ifndef __GMP_H__
#include <gmp.h>
#endif

#ifndef _STDIO_H
#include <stdio.h>
#endif

#ifndef _STDLIB_H
#include <stdlib.h>
#endif

#ifndef _STRING_H
#include <string.h>
#endif

#define NTH_ERROR_UNSPECIFIED  1
#define NTH_ERROR_NULL_POINTER 2
#define NTH_ERROR_NO_MEMORY    3
#define NTH_ERROR_ZERO_LENGTH  4
#define NTH_ERROR_OVERFLOW     5
#define NTH_ERROR_LESS_THAN    6
#define NTH_ERROR_GREATER_THAN 7

struct Nth_Number;
struct Nth_Plugin;
struct Nth_Program;

struct Nth_Number {
	void * number_buffer;
	size_t number_length;
};

struct Nth_Variable {
	char * variable_name;
	char * variable_value;
};

struct Nth_Addition {
	struct Nth_Number operand_one;
	struct Nth_Number operand_two;
	struct Nth_Number sum;
};

struct Nth_Division {
	struct Nth_Number operand_one;
	struct Nth_Number operand_two;
	struct Nth_Number quotient;
	struct Nth_Number remainder;
};

struct Nth_Multiplication {
	struct Nth_Number operand_one;
	struct Nth_Number operand_two;
	struct Nth_Number product;
};

struct Nth_Subtraction {
	struct Nth_Number operand_one;
	struct Nth_Number operand_two;
	struct Nth_Number difference;
	struct Nth_Number underflow;
};

struct Nth_Plugin {

	void * library_handle;

	char * plugin_name;
	char * plugin_description;

	int (*plugin_callback)(
		struct Nth_Program * nth_program,
		struct Nth_Number * result
	);
};

struct Nth_Program {

	int argc;
	char ** argv;
	int arg_index;

	size_t stack_index;

	size_t variable_count;
	struct Nth_Variable * variable_array;

	size_t plugin_count;
	struct Nth_Plugin * plugin_array;

	size_t failure_count;
	char ** failure_messages;
	char ** failure_functions;
};

/* Functions for working with
 * paths
 */

int Create_Nth_Path(char ** nth_path);
int Destroy_Nth_Path(char ** nth_path);

int Export_Nth_Directory(char * nth_path);

int Append_Nth_Path(char ** nth_path, char * append_path);
int Prepend_Nth_Path(char ** nth_path, char * prepend_path);

int Set_Nth_Path_Prefix(char ** nth_path, char * prefix_path);
int Set_Nth_Path_Suffix(char ** nth_path, char * suffix_path);

/* Functions for working
 * with files
 */

int Get_Nth_File_Size(char * file_name, size_t * file_size);

int Read_Nth_File(char * file_name, void * read_buffer, size_t buffer_size);
int Write_Nth_File(char * file_name, void * write_buffer, size_t buffer_length);

/* Functions for converting strings to
 * arbitrary precision numbers, or vice
 * versa
 */

int Parse_Hex_Nth_Number (char * string, size_t string_length, struct Nth_Number * number);
int Parse_Dec_Nth_Number (char * string, size_t string_length, struct Nth_Number * number);
int Parse_Oct_Nth_Number (char * string, size_t string_length, struct Nth_Number * number);
int Parse_Bin_Nth_Number (char * string, size_t string_length, struct Nth_Number * number);

int Write_Hex_Nth_Number (struct Nth_Number * number, char * string, size_t string_length);
int Write_Dec_Nth_Number (struct Nth_Number * number, char * string, size_t string_length);
int Write_Oct_Nth_Number (struct Nth_Number * number, char * string, size_t string_length);
int Write_Bin_Nth_Number (struct Nth_Number * number, char * string, size_t string_length);

/* Functions for working
 * with nth numbers
 */

int Clean_Nth_Number      (struct Nth_Number * nth_number);
int Set_Nth_Number_Length (struct Nth_Number * nth_number, size_t new_length);
int Set_Nth_Number_Value  (struct Nth_Number * nth_number, size_t new_value);

int Add_Nth_Numbers      (struct Nth_Addition * nth_addition);
int Divide_Nth_Numbers   (struct Nth_Division * nth_division);
int Multiply_Nth_Numbers (struct Nth_Multiplication * nth_multiplication);
int Subtract_Nth_Numbers (struct Nth_Subtraction * nth_subtraction);

/* Functions for using
 * plugins
 */

int Clean_Nth_Plugin(struct Nth_Plugin * nth_plugin);
int Initialize_Nth_Plugin(struct Nth_Plugin * nth_plugin);

int Link_Nth_Plugins(struct Nth_Program * nth_program);
int Unlink_Nth_Plugins(struct Nth_Program * nth_program);

int Nth_Plugin_Callback(struct Nth_Program * nth_program, struct Nth_Number * nth_number);

int Push_Nth_Plugin(struct Nth_Program * nth_program, struct Nth_Plugin * nth_plugin);

/* Functions for working
 * with the program.
 */

int Create_Nth_Program(struct Nth_Program ** nth_program);
int Destroy_Nth_Program(struct Nth_Program ** nth_program);

int Evaluate_Nth_Expression(struct Nth_Program * nth_program, struct Nth_Number * nth_number);
int Export_Nth_Results(struct Nth_Program * nth_program, struct Nth_Number * number_array, size_t number_count);

int Get_Next_Nth_Argument(struct Nth_Program * nth_program, char ** next_argument);
int Iterate_Nth_Argument(struct Nth_Program * nth_program);

int Set_Nth_Variable(struct Nth_Program * nth_program, struct Nth_Variable * nth_variable);
int Get_Nth_Variable(struct Nth_Program * nth_program, struct Nth_Variable * nth_variable);

int Print_Nth_Failures(struct Nth_Program * nth_program);
int Push_Nth_Failure(struct Nth_Program * nth_program, char * function_name, char * error_message);

int Read_Nth_Stack_Index(struct Nth_Program * nth_program);
int Write_Nth_Stack_Index(struct Nth_Program * nth_program);

#endif

